package org.hilo.boot.app.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.ResourceLoader;

import org.hilo.boot.core.spring.FixedLogbackLoggingSystem;

/**
 * wrap of SpringApplication
 * @see SpringApplication
 * 
 * @author zollty
 * @since 2018-3-2
 */
public class MainApplication extends SpringApplication {
    private static final Banner DEFAULT_BANNER = new HiloBootBanner();
    
    public MainApplication(Class<?>... primarySources) {
        super(primarySources);
    }

    public MainApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        super(resourceLoader, primarySources);
    }
    
    /**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
    @Override
    public ConfigurableApplicationContext run(String... args) {
        // MainApplication.configure(application, args);
        // 自定义配置加载，很早的时候执行
        // this.addListeners(new EnvironmentPropertyPostProcessor());
        long t1 = System.currentTimeMillis();
        Logger logger = LoggerFactory.getLogger(MainApplication.class);
        logger.info("SpringBoot ready to start...birthTime=" + t1);
        // 自定义 LogbackLoggingSystem
        System.setProperty("org.springframework.boot.logging.LoggingSystem", FixedLogbackLoggingSystem.class.getName());
        
        super.setBanner(DEFAULT_BANNER);
        
        ConfigurableApplicationContext ret = super.run(args);
        
        long t2 = System.currentTimeMillis();
        logger = LoggerFactory.getLogger(MainApplication.class);
        logger.info("SpringBoot Start Success in " + ((t2 - t1) / 1000) + " seconds.");
        return ret;
    }
    
//    @Override
//    protected void bindToSpringApplication(ConfigurableEnvironment environment) {
//        super.bindToSpringApplication(environment);
//        String swa = environment.getProperty("hilo.skywalking.enable");
//        if ("true".equalsIgnoreCase(swa)) {
//            SwTrace.initLogbackTraceExtention();
//        }
//    }
    
    public static SpringApplicationBuilder builder() {
        SpringApplicationBuilder builder = new MainSpringApplicationBuilder();
        return builder;
    }

    /**
     * Static helper that can be used to run a {@link SpringApplication} from the
     * specified sources using default settings and user supplied arguments.
     * @param sources the sources to load
     * @param args the application arguments (usually passed from a Java main method)
     * @return the running {@link ApplicationContext}
     */
    public static ConfigurableApplicationContext run(Class<?>[] sources, String[] args) {
        return new MainApplication(sources).run(args);
    }
    
    /**
     * Static helper that can be used to run a {@link SpringApplication} from the
     * specified source using default settings.
     * @param source the source to load
     * @param args the application arguments (usually passed from a Java main method)
     * @return the running {@link ApplicationContext}
     */
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }
    
    /**
     * A basic main that can be used to launch an application. This method is useful when
     * application sources are defined via a {@literal --spring.main.sources} command line
     * argument.
     * <p>
     * Most developers will want to define their own main method and call the
     * {@link #run(Object, String...) run} method instead.
     * @param args command line arguments
     * @throws Exception if the application cannot be started
     * @see SpringApplication#run(Object[], String[])
     * @see SpringApplication#run(Object, String...)
     */
    public static void main(String[] args) throws Exception {
        MainApplication.run(new Class<?>[] {MainApplication.class}, args);
    }

}
